package com.blockchain.securewallet.utils;

import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;


public class Logger {

    private static Logger instance;
    private static final String LOG_TAG = "==w";
    private static final String TIME_FORMAT = "yyyy-MM-dd hh:mm";
    private static final String STATISTICS_NAME = "log.log_";
    private static final String CRASH_NAME = "crash.log_";
    private static final int LOG_FILE_SIZE_LIMIT = 5; // 单位mb

    public static Logger getInstance() {
        if (instance == null) {
            synchronized (Logger.class) {
                if (instance == null) {
                    instance = new Logger();
                }
            }
        }
        return instance;
    }

    private String getFunctionName() {
        StackTraceElement[] sts = Thread.currentThread().getStackTrace();

        if (sts == null) {
            return null;
        }

        for (StackTraceElement st : sts) {
            if (st.isNativeMethod()) {
                continue;
            }

            if (st.getClassName().equals(Thread.class.getName())) {
                continue;
            }

            if (st.getClassName().equals(this.getClass().getName())) {
                continue;
            }
            return "["
                    + Thread.currentThread().getName()
                    + "("
                    + Thread.currentThread().getId()
                    + "): "
                    + st.getFileName()
                    + ":"
                    + st.getLineNumber()
                    + "]";
        }

        return null;
    }

    @SuppressWarnings("unused")
    private String createMessage(String msg) {
        String functionName = getFunctionName();
        String message = (functionName == null ? msg : (functionName + " - " + msg));
        return message;
    }

    /**
     * log.i
     */
    public void info(String msg) {
        this.info(LOG_TAG, msg);
    }

    /**
     * log.i
     */
    public void info(String tag, String msg) {
        Log.i(tag, wrapLogWithMethodLocation(msg));
    }

    /**
     * log.v
     */
    public void verbose(String msg) {
        this.verbose(LOG_TAG, msg);
    }

    /**
     * log.v
     */
    public void verbose(String tag, String msg) {
        Log.v(tag, wrapLogWithMethodLocation(msg));
    }

    /**
     * log.d
     */
    public static void d(String msg) {
        Logger.getInstance().debug(LOG_TAG, msg);
    }

    /**
     * log.d
     */
    public static void ds(String msg) {
        Logger.getInstance().debugs(LOG_TAG, msg);
    }

    /**
     * 这个是不显示行号的log
     * log.d
     */
    public void debug(String tag, String msg) {
        Log.d(tag, wrapLog(msg));
    }

    /**
     * log.d
     */
    public void debugs(String tag, String msg) {
        Log.d(tag, wrapLogWithMethodLocation(msg));
    }


    private void writeToFile(File logFile, String msg) {
        FileWriter writer = null;
        try {
            if (!logFile.exists()) {
                logFile.createNewFile();
            }
            if ((logFile.length() / 1024 / 1024) > LOG_FILE_SIZE_LIMIT) {
                writer = new FileWriter(logFile, false);
            } else {
                writer = new FileWriter(logFile, true);
            }
            writer.write(msg);
        } catch (IOException e) {
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
            }
        }
    }

    /**
     * 代码定位
     */
    private String wrapLogWithMethodLocation(String msg) {
        StackTraceElement[] stack = Thread.currentThread().getStackTrace();
        int i = 0;
        //获取代码所运行的位置
        for (StackTraceElement e : stack) {
            String name = e.getClassName();
            if (!name.equals(Logger.class.getName())) {
                i++;
            } else {
                break;
            }
        }
        //进行方法位置偏移
        i += 3;
        //当我能准确获取到I时，本部分已经完结，以下代码都是废话，请不要关注
        String className = stack[i].getFileName();
        String methodName = stack[i].getMethodName();
        int lineNumber = stack[i].getLineNumber();
        StringBuilder sb = new StringBuilder();
        msg = wrapJson(msg);
        sb.append("#(").append(className).append(":").append(lineNumber).append(")# ").append(":").append('\n')
                .append("\t\t\t\t\t>> " + methodName + ":\n\t\t\t\t\t\t\t\t\t").append(msg);
        return sb.toString();
    }

    public String wrapJson(String jsonStr) {
        String message;
        try {
            if (jsonStr.startsWith("{")) {
                JSONObject jsonObject = new JSONObject(jsonStr);
                message = jsonObject.toString(4);
                message = ">>>>>>>>>>>>>>JSONObject>>>>>>>>>>>>>>\n"
                        + "   " + message + '\n'
                        + "<<<<<<<<<<<<<JSONObject<<<<<<<<<<<<<\n";
            } else if (jsonStr.startsWith("[")) {
                JSONArray jsonArray = new JSONArray(jsonStr);
                message = jsonArray.toString(4);
                message = ">>>>>>>>>>>>>>JSONArray>>>>>>>>>>>>>>\n"
                        + "   " + message + '\n'
                        + "<<<<<<<<<<<<<JSONArray<<<<<<<<<<<<<\n";
            } else {
                message = jsonStr;
            }
        } catch (JSONException e) {
            message = jsonStr;
        }

        return message;
    }


    /**
     * 代码定位
     */
    private String wrapLog(String msg) {
        StackTraceElement[] stack = Thread.currentThread().getStackTrace();
        int i = 0;
        //获取代码所运行的位置
        for (StackTraceElement e : stack) {
            String name = e.getClassName();
            if (!name.equals(Logger.class.getName())) {
                i++;
            } else {
                break;
            }
        }
        //进行方法位置偏移
        i += 3;
        //当我能准确获取到I时，本部分已经完结，以下代码都是废话，请不要关注
        String methodName = stack[i].getMethodName();

        StringBuilder sb = new StringBuilder();
        msg = wrapJson(msg);
        sb.append(">> " + methodName + ":\t\t").append(msg);

        return sb.toString();
    }


}
